#include "CtrlBox.h"

#include <vector>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>


#pragma comment(lib, "Ws2_32.lib")

class CtrlBoxPrivate
{
public:
    SOCKET socket;
    sockaddr_in serverAddr;
    sockaddr_in localAddr;
    WSADATA wsaData;
    bool isOpened;
};

CtrlBox::CtrlBox()
{
    dCtrlBox = new CtrlBoxPrivate();
    //初始化 win socket
    WSAStartup( MAKEWORD(2, 2), &(dCtrlBox->wsaData) ) ;

    ZeroMemory( &dCtrlBox->serverAddr, sizeof(dCtrlBox->serverAddr));

    dCtrlBox->socket = 0;
}

CtrlBox::~CtrlBox()
{
    clostHost();

    delete dCtrlBox;
}

void CtrlBox::setServerAddress(const std::string &add, int port)
{
    // 设置服务器地址

    dCtrlBox->serverAddr.sin_family = AF_INET;
    dCtrlBox->serverAddr.sin_port = htons(port); // 端口号
    // inet_pton(AF_INET, "192.168.1.1", &dCtrlBox->serverAddr.sin_addr);// 服务器IP地址
    dCtrlBox->serverAddr.sin_addr.s_addr = inet_addr(add.data()); // 服务器IP地址
}

void CtrlBox::setLocalAddress(const std::string &add, int port)
{
    // 设置本地地址

    dCtrlBox->localAddr.sin_family = AF_INET;
    dCtrlBox->localAddr.sin_port = htons(port); // 端口号
    // inet_pton(AF_INET, "192.168.1.1", &dCtrlBox->serverAddr.sin_addr);// 服务器IP地址
    dCtrlBox->localAddr.sin_addr.s_addr = inet_addr(add.data()); // 服务器IP地址
}


std::string CtrlBox::getLocalAddress()
{
    // 获取IP地址
    char ip_str[INET_ADDRSTRLEN]; // INET_ADDRSTRLEN是IPv4地址字符串的最大长度

    inet_ntop(AF_INET, &dCtrlBox->localAddr.sin_addr, ip_str, sizeof(ip_str));

    return std::string( ip_str );
}

int CtrlBox::getLocalPort()
{
    return ntohs(dCtrlBox->localAddr.sin_port );
}

std::string CtrlBox::getServerAddress()
{
    // 获取IP地址
    char ip_str[INET_ADDRSTRLEN]; // INET_ADDRSTRLEN是IPv4地址字符串的最大长度

    inet_ntop(AF_INET, &dCtrlBox->serverAddr.sin_addr, ip_str, sizeof(ip_str));

    return std::string( ip_str );
}

int CtrlBox::getServerPort()
{
    return ntohs(dCtrlBox->serverAddr.sin_port );
}

bool CtrlBox::openHost()
{
    if( dCtrlBox->isOpened )
    {
        clostHost();
    }

    // 创建 Socket
    dCtrlBox->socket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    if ( dCtrlBox->socket == INVALID_SOCKET)
    {
        std::cout<<"Could not create socket : "<< WSAGetLastError()<< std::endl ;

        WSACleanup();

        dCtrlBox->isOpened = false;

        return false;
    }

    dCtrlBox->isOpened = true;

    return true;
}

void CtrlBox::clostHost()
{
    // 清理资源
    closesocket( dCtrlBox->socket );

    dCtrlBox->isOpened = false;

    WSACleanup();
}

bool CtrlBox::sendData( const char* data, int dataLen )
{

    if( ! dCtrlBox->isOpened )
    {
        return false;
    }
    // 发送数据
    auto sendResult = sendto( dCtrlBox->socket,
                             data ,
                             dataLen ,
                             0,
                             (SOCKADDR*)&dCtrlBox->serverAddr,
                             sizeof(dCtrlBox->serverAddr));

    if (sendResult == SOCKET_ERROR)
    {
        std::cout<<"Send failed with error code : "<< WSAGetLastError()<< std::endl ;

        return false;
    }

    return true;
}

char *CtrlBox::readData(unsigned int size )
{
    if( size == 0 || (! dCtrlBox->isOpened) )
    {
        return nullptr;
    }

    char* buffer = new char[size];

    // 接收响应
    socklen_t addrLen = sizeof( dCtrlBox->localAddr );

    int readLen = recvfrom( dCtrlBox->socket,
                            buffer,
                            size,
                            0,
                            (struct sockaddr *)&dCtrlBox->localAddr,
                            &addrLen );

    if (readLen < 0)
    {
        std::cout<<"recvfrom failed with error code : "<< WSAGetLastError()<< std::endl ;

        delete [] buffer;
        buffer = nullptr;

    }
    return buffer;
}
